﻿using System;
using System.Collections.Generic;
using DimOS.Constants;
using DimOS.DimFS;
using DimOS.DimSH;
using DimOS.Internals;
using DimOS.Plugs;
using Array = DimOS.Plugs.Array;
using Char = DimOS.Plugs.Char;
using Convert = DimOS.Plugs.Convert;
using Math = System.Math;
using String = DimOS.Plugs.String;
using HAL = Cosmos.Hardware;
using UI = DimOS.DimSH.Interface;
using SH = DimOS.DimSH.Shell;

namespace DimOS.H
{
    public static class Parser
    {
        public static Value Process(Script source, char[] stop, bool execute = true, int end = -1)
        {
            var list = Divide(source, stop, execute, end); if
            (!execute) return Value.Empty; if (list.Count == 0)
            throw new InvalidOperationException("Failed to " +
            "process chunk [" + source.Substring(source.Pointer,
            Engine.OutputLimit) + "]."); if (list.Count == 1)
            return list[0]; var index = 1; return Conquer(list
            [0], ref index, list, false);
        }

        private static string GetOperation(string source)
        {
            for (int i = 0; i < Tokens.Operations.Length; i++) if (String.StartsWith
            (source, Tokens.Operations[i])) return Tokens.Operations[i]; return null;
        }

        private static List<Value> Divide(Script source, char[] stop, bool execute = true, int end = -1)
        {
            var negated = 0; var parameterLeft = 1; var parameterRight = 0; var silent
            = false; var list = new List<Value>(); var enclosed = false; var level = 0;
            if (!source.Valid || Array.Contains(stop, source.Data[source.Pointer])) {
            list.Add(Value.Empty); source.Traverse(1); return list; } var token = "";
            var until = HAL.RTC.Second + 1; if (until > 59) until -= 60;

            do
            {
                HAL.Keyboard.KeyMapping mapping; if (HAL.Global.Keyboard.GetMapping
                (out mapping) && mapping != null) if (execute) { if (mapping.Key ==
                ConsoleKey.Escape) throw new OperationCanceledException("Operation "
                + "canceled by user."); } else { source.Pointer = source.Data.Length;
                return list; } if (until == HAL.RTC.Second || until == HAL.RTC.Second
                - 1) { UI.DrawClock(false); until = HAL.RTC.Second + 1; if (until >
                59) until -= 60; }

                var not = source.Substring(source.Pointer, Engine.ProcessLimit);
                if (!enclosed && not[0] == Tokens.Not && (not.Length == 1 || (not
                [1] != Tokens.Equal[0] && not[1] != Tokens.Less[0] && not[1] !=
                Tokens.More[0] && not[1] != Tokens.Like[0] && not[1] != Tokens
                .LoopShort && not[1] != Tokens.DefineShort && not[1] != Tokens
                .TerminalShort && not[1] != Tokens.IfShort[0] && not[1] != Tokens
                .WaitShort[0]))) { for (int i = 0; i < Commands.List[0].Count;
                i++) { var key = Commands.List[0][i].Key; if (String.StartsWith
                (not, Tokens.Not + key + Tokens.Dot)) { silent = true; break; }
                for (int j = 0; j < Commands.List[0][i].Aliases.Length; j++) { var
                alias = Commands.List[0][i].Aliases[j]; if (String.StartsWith(not,
                Tokens.Not + alias + Tokens.Dot)) { silent = true; break; } } }
                source.Traverse(1); if (!silent) negated++; continue; } if (String
                .StartsWith(not, Tokens.WaitShort)) token += Tokens.WaitShort[0];

                var character = source.Data[source.Pointer++]; switch (character)
                {
                    case Tokens.VerbatimString: if (!enclosed || (source.Data[source
                    .Pointer - 2] != Tokens.MirrorLeft && source.Data[source.Pointer
                    - 2] != Tokens.MirrorRight)) enclosed = !enclosed; break;
                        
                    case Tokens.ValueLeft: if (!enclosed) level++; break;
           
                    case Tokens.ValueRight: if (!enclosed) level--; break;

                    case Tokens.ParameterLeft: if (!enclosed && Array.Contains
                    (stop, Tokens.ParameterLeft)) parameterLeft++; break;

                    case Tokens.ParameterRight: if (!enclosed && Array.Contains
                    (stop, Tokens.ParameterLeft)) parameterRight++; break;
                }

                string action = null; var collect = enclosed || level > 0;
                if (collect == false) { var temp = source.Pointer >= 1 ? source
                .Data[source.Pointer - 1] : Tokens.Empty; if (!(Array.Contains
                (stop, temp) || temp == Tokens.ParameterLeft || temp == Tokens
                .CommandLeft || source.Pointer >= source.Data.Length)) { if ((
                token.Length == 0 && ((temp == Tokens.Subtract && (source.Pointer
                < source.Data.Length ? source.Data[source.Pointer] : Tokens.Empty)
                != Tokens.Subtract) || temp == Tokens.ValueRight || temp == Tokens
                .ParameterRight)) || (Char.ToUpper(source.Pointer >= 2 ? source
                .Data[source.Pointer - 2] : Tokens.Empty) == 'E' && (temp == Tokens
                .Subtract || temp == Tokens.Add || Char.IsDigit(temp)) && token
                .Length > 1 && Char.IsDigit(token[token.Length - 2]))) collect =
                true; else if (!((action = GetOperation(source.Substring(source
                .Pointer - 1, Engine.ProcessLimit))) != null || (token.Length >
                0 && temp == Tokens.Space))) collect = true; } } if (collect) {
                token += character; if (source.Valid && (enclosed || level > 0
                || !Array.Contains(stop, source.Data[source.Pointer])) && (end
                < 0 || source.Pointer < end)) continue; }

                if (List.Contains(Tokens.FlowControl, token) && list.Count > 0 && execute)
                { throw new InvalidOperationException("Wrong token encountered (" + token +
                ") at [" + source.Substring(source.Pointer - 1, Engine.OutputLimit) + "].");
                } var before = source.Pointer - token.Length - 1; //Needed to skip statements

                if (source.Valid && source.Data[source.Pointer] == Tokens.Space) { var skip =
                true; for (int i = 0; i < Tokens.SpaceRestore.Count; i++) if (String.StartsWith
                (token, Tokens.SpaceRestore[i]) && token != Tokens.SpaceRestore[i]) { skip =
                false; break; } if (skip) source.Traverse(1); } if (action != null && action
                .Length > 1) source.Traverse(action.Length - 1);

                if (token.Length > 1) { if (String.StartsWith(token, Tokens.ElseShort)) { source
                .Pointer -= token.Length - Tokens.ElseShort.Length; token = Tokens.ElseShort; }
                else if (String.StartsWith(token, Tokens.BreakShort)) { source.Pointer -= token
                .Length - Tokens.BreakShort.Length; token = Tokens.BreakShort; } else if (String
                .StartsWith(token, Tokens.ContinueShort)) {source.Pointer -= token.Length - Tokens
                .ContinueShort.Length; token = Tokens.ContinueShort; } else if (String.StartsWith
                (token, Tokens.WaitShort)) { source.Pointer -= token.Length - Tokens.WaitShort.Length;
                token = Tokens.WaitShort; } else for (int i = 0; i < Commands.List[0].Count; i++) {
                var key = Commands.List[0][i].Key; if (String.StartsWith(token, key + Tokens.Dot))
                { source.Pointer -= token.Length - key.Length; token = key; break; } for (int j =
                0; j < Commands.List[0][i].Aliases.Length; j++) { var alias = Commands.List[0][i]
                .Aliases[j]; if (String.StartsWith(token, alias + Tokens.Dot)) { source.Pointer -= 
                token.Length - alias.Length; token = key; break; } } } } for (int k = 0; k < Commands
                .List[0].Count; k++) { var key = Commands.List[0][k].Key; if (token == key && !silent
                && source.Pointer - token.Length - 1 >= 0 && source.Data[source.Pointer - token.Length
                - 1] == Tokens.Not) {silent = true; break; } }

                Value value; if (execute) { value = new Function(source, token, character, ref action).Call
                (source, silent); if (value.Return) { list.Add(value); return list; } } else { value = Value
                .Empty; var current = source.Pointer; if (List.Contains(Commands.List[0], token)) CheckShell
                (source, token, before); else if (token == Tokens.Loop || token == Tokens.LoopShort.ToString
                ()) CheckLoop(source, before);  else if (token == Tokens.If || token == Tokens.IfShort) {
                CheckConditional(source, true); source.Pointer = current; CheckConditional(source, false); 
                } else if (token == Tokens.Try || token == Tokens.TryShort) CheckTry(source, before); else
                if (token == Tokens.Define || token == Tokens.DefineShort.ToString()) CheckFunction(source,
                before); else if (token == Tokens.Else || token == Tokens.ElseIf || token == Tokens.ElseShort)
                new SafetyPlug().Call(source, silent); else { if (Function.Exists(token) && !Array.Contains
                (Tokens.Operations, action)) { source.Pointer = before + token.Length; CheckStatement(source);
                } else if (Array.Contains(Tokens.Operations, action)) source.GetConstruct(); else SkipChunk
                (source); } while (source.Valid && (source.Pointer == current || source.Pointer == before ||
                source.Pointer == before + token.Length || Array.Contains(Tokens.ListProcess, source.Data
                [source.Pointer]))) source.Traverse(1); if (!source.Valid) return list; }
                
                if (negated > 0 && (value.Type == ValueType.Number || value.Type ==
                ValueType.String)) { value = new Value(Convert.ToFloat(!((negated % 2 ==
                0) ^ (value.Type == ValueType.Number ? Convert.ToBoolean(value.Number) :
                (value.String.ToLower() == "true" || value.String == "1"))))); negated = 0; }

                if (action == null) { if (!source.Valid || source.Data[source.Pointer] ==
                Tokens.ParameterRight || Array.Contains(stop, source.Data[source.Pointer])
                || (end >= 0 && source.Pointer >= end)) action = Tokens.ParameterRight
                .ToString(); else { action = GetOperation(source.Substring(source.Pointer,
                Engine.ProcessLimit)); source.Traverse(action == null ? 0 : action.Length);
                action = action ?? Tokens.ParameterRight.ToString(); } } else if (source
                .Valid && source.Data[source.Pointer] == action[0]) source.Traverse(1);

                if (list.Count == 0 && ((source.Pointer < source.Data.Length ? source
                .Data[source.Pointer] : Tokens.Empty) == Tokens.End || (action == Tokens
                .ParameterRight.ToString() && /*value.Type != ValueType.Number*/ parameterLeft == parameterRight))) { if
                (action != null && action != Tokens.ParameterRight.ToString()) throw
                new InvalidOperationException("Wrong operation encountered (" + action
                + ")."); list.Add(value); return list; } value = new Value(value) {
                Action = action }; if (value.Type == ValueType.Number && ((value.Action
                == Tokens.And && value.Number != 1) || (value.Action == Tokens.Or &&
                value.Number == 1))) { var count = 0; var trigger = false; var temp =
                Tokens.Empty; while(source.Valid) { var current = source.Data[source
                .Pointer]; if (trigger && current != Tokens.VerbatimString) { source
                .Traverse(1); continue; } if (current == Tokens.VerbatimString) { if
                (/*temp == Tokens.Empty*/!trigger || (temp != Tokens.MirrorLeft && temp != Tokens
                .MirrorRight)) trigger = !trigger; } else if (!trigger && current ==
                Tokens.ParameterLeft) count++; else if (!trigger && current == Tokens
                .ParameterRight) { count--; if (count < 0) break; } else if (!trigger
                && (current == Tokens.Separator || current == Tokens.End)) break; source
                .Traverse(1); temp = current; } value.Action = Tokens.ParameterRight
                .ToString(); } list.Add(value); token = "";

            } while (source.Valid && (enclosed || level > 0 || !Array.Contains(stop, source
            .Data[source.Pointer])) && (end < 0 || source.Pointer < end)); if (source.Valid &&
            source.Data[source.Pointer] == Tokens.ParameterRight) source.Traverse(1); return list;
        }

        private static Value Conquer(Value source, ref int index, List<Value> list, bool once = true)
        {
            var trigger = true; while (index < list.Count)
            { var target = list[index++]; while (GetPriority(source.Action)
              < GetPriority(target.Action)) Conquer(target, ref index, list);
              if (source.Type != ValueType.Break && source.Type != ValueType.Continue)
              {
                //=============================================================================
                if (source.Type == ValueType.Number && target.Type == ValueType.Number) trigger
                = ProcessNumbers(source, target, trigger); else if (source.Type == ValueType
                .List || target.Type == ValueType.List) trigger = ProcessLists(source, target,
                trigger); else trigger = ProcessStrings(source, target, trigger);
                //=============================================================================
                source.Action = target.Action;
              } if (once) break;
            } return source;
        }

        public static bool ProcessNumbers(Value source, Value target, bool trigger = true)
        {
            var left = source.Number; var right = target.Number;
            
            if (source.Action == Tokens.Add.ToString()) source.Number = left + right;

            else if (source.Action == Tokens.Subtract.ToString()) source.Number = left - right;

            else if (source.Action == Tokens.Multiply.ToString()) source.Number = left * right;

            else if (source.Action == Tokens.Divide.ToString()) { if (target.Number == 0) throw
            new InvalidOperationException("Division by zero."); source.Number = left / right; } 

            else if (source.Action == Tokens.Remainder.ToString()) { if (target.Number == 0) throw new
            InvalidOperationException("Division by zero."); source.Number = Plugs.Math.Remainder(left, right); } 

            else if (source.Action == Tokens.Power.ToString())
            source.Number = (float)Math.Pow(left, right);

            else if (source.Action == Tokens.Index.ToString())
            if (right == 0) { if (left == 0) source.Number = Math
            .Abs(left.Round()); else source.Number = -1; } else
            if (right < 0) { if (!(left > 0) && left >= right)
            source.Number = Math.Abs(left.Round()); else source
            .Number = -1; } else { if (!(left < 0) && left <=
            right) source.Number = Math.Abs(left.Round());
            else source.Number = -1; }
                
            else if (source.Action == Tokens.Less)
            source.Number = Convert.ToFloat(left < right);
                        
            else if (source.Action == Tokens.More)
            source.Number = Convert.ToFloat(left > right);
                        
            else if (source.Action == Tokens.LessOrEqual
            || source.Action == Tokens.NotMore) source
            .Number = Convert.ToFloat(left <= right);
                        
            else if (source.Action == Tokens.MoreOrEqual
            || source.Action == Tokens.NotLess) source
            .Number = Convert.ToFloat(left >= right);
                        
            else if (source.Action == Tokens.Equal)
            source.Number = Convert.ToFloat(left == right);
                        
            else if (source.Action == Tokens.NotEqual)
            source.Number = Convert.ToFloat(left != right);
                        
            else if (source.Action == Tokens.And)
            source.Number = Convert.ToFloat(Convert
            .ToBoolean(left) && Convert.ToBoolean(right));

            else if (source.Action == Tokens.Xor)
            source.Number = Convert.ToFloat(Convert
            .ToBoolean(left) ^ Convert.ToBoolean(right));
                        
            else if (source.Action == Tokens.Or)
            source.Number = Convert.ToFloat(Convert
            .ToBoolean(left) || Convert.ToBoolean(right));

            else if (source.Action == Tokens.NotLike)
            source.Number = Convert.ToFloat(Convert
            .ToInt32(left.Round()) - Convert.ToInt32
            (right.Round()) != 0);

            else if (source.Action == Tokens.Like)
            source.Number = Convert.ToFloat(Convert
            .ToInt32(left.Round()) - Convert.ToInt32
            (right.Round()) == 0);

            else if (source.Action == Tokens.LessLike)
            source.Number = Convert.ToFloat(Convert
            .ToInt32(left.Round()) < Convert.ToInt32
            (right.Round()));

            else if (source.Action == Tokens.MoreLike)
            source.Number = Convert.ToFloat(Convert
            .ToInt32(left.Round()) > Convert.ToInt32
            (right.Round()));

            else if (source.Action == Tokens.In) if (right
            == 0) source.Number = Convert.ToFloat(left == 0);
            else if (right < 0) source.Number = Convert.ToFloat
            (!(left > 0) && left >= right); else source.Number
            = Convert.ToFloat(!(left < 0) && left <= right);

            else if (source.Action == Tokens.NotIn) if (right
            == 0) source.Number = Convert.ToFloat(left != 0);
            else if (right < 0) source.Number = Convert.ToFloat
            (left > 0 || left < right); else source.Number =
            Convert.ToFloat(left < 0 || left > right);

            else if (source.Action == Tokens.Ternary) if (trigger
            == false) trigger = true; else { source.Number = right;
            if (Convert.ToBoolean(left)) trigger = false; }

            else if (source.Action == Tokens.Convert.ToString()) { }

            return trigger;
        }

        public static bool ProcessLists(Value source, Value target, bool trigger = true)
        {
            var left = new Value(source); var right = new Value(target);
            
            if (source.Action == Tokens.Add.ToString()) if (source.Type == ValueType.List &&
            target.Type == ValueType.List) for (int i = 0; i < target.List.Count; i++) source
            .List.Add(target.List[i]); else if (source.Type == ValueType.List) source.List.Add
            (target); else { List.Insert(right.List, 0, left); source.List = right.List; }
            
            else if (source.Action == Tokens.Subtract.ToString()) if (source.Type == ValueType
            .List && target.Type == ValueType.List) List.Remove(source.List, right.List); else
            if (source.Type == ValueType.List) List.Remove(source.List, right); else { left =
            new Value(Convert.ToList(left)); List.Remove(left.List, right.List); source.List =
            left.List; } 
            
            else if (source.Action == Tokens.Multiply.ToString()) if (source.Type == ValueType
            .List && target.Type == ValueType.List) for (int i = 1; i < target.List.Count; i++)   
            for (int j = 0; j < left.List.Count; j++) source.List.Add(left.List[j]); else if
            (target.Type == ValueType.Number) for (int i = 1; i < Convert.ToInt32(Math.Abs
            (right.Number.Round())); i++) for (int j = 0; j < left.List.Count; j++) source
            .List.Add(left.List[j]); else if (target.Type == ValueType.String) for (int i = 1;
            i < right.String.Length; i++) for (int j = 0; j < left.List.Count; j++) source.List
            .Add(left.List[j]); else { left = new Value(Convert.ToList(left)); source.List = new
            List<Value> { left }; for (int i = 1; i < target.List.Count; i++) for (int j = 0; j
            < left.List.Count; j++) source.List.Add(left.List[j]); }

            else if (source.Action == Tokens.Divide.ToString()) if (target.Type == ValueType
            .Number) { var count = Convert.ToInt32(Math.Abs(target.Number.Round())); if (count >
            left.List.Count) throw new InvalidOperationException("Split index (" + count + ") was"
            + "out of range [" + left.List.Count + "]."); source.List = new List<Value>(); var stop
            = Convert.ToInt32(Math.Abs(left.List.Count / count)); if (left.List.Count % count != 0)
            stop++; for (int i = 0; i < stop; i++) { source.List.Add(new Value(i == stop - 1 ? left
            .List : left.List.GetRange(0, count))); if (i != stop - 1) left.List.RemoveRange(0,
            count); } } /*else {
            var split = String.Split(left, right, true); source.List = new List<Value>(); for
            (int i = 0; i < split.Count; i++) source.List.Add(new Value(split[i])); }*/

            //else if (source.Action == Tokens.Remainder.ToString()) if (target.Type == ValueType
            //.Number) { var count = Convert.ToInt32(Math.Abs(target.Number.Round())); if (count
            //*2 > left.Length) throw new InvalidOperationException("Trim index (" + count + ")" +
            //" was out of range [" + left.Length + "]."); source.String = left.Remove(0, count);
            //source.String = source.String.Remove(source.String.Length - count); } else { if
            //(right == "") return false; if (right.Length == 1) source.String = String.Trim(left,
            //right[0]); else { while (String.StartsWith(left, right)) left = left.Remove(0, right
            //.Length); while (String.EndsWith(left, right)) left = left.Remove(left.Length -
            //right.Length); source.String = left; } }

            //else if (source.Action == Tokens.Power.ToString()) if (target.Type == ValueType
            //.Number) { if (Convert.ToInt32(target.Number.Round()) > 0) source.String = left
            //.ToUpper(); else if (Convert.ToInt32(target.Number.Round()) < 0) source.String =
            //left.ToLower(); else { source.String = left; } } else { if (right == "") return
            //false; var temp = right.ToCharArray(); for (int i = 0; i < temp.Length; i++) if
            //(temp[i] >= 'A' && temp[i] <= 'Z') temp[i] = (char)(temp[i] | 0x20); else if
            //(temp[i] >= 'a' && temp[i] <= 'z') temp[i] = (char)(temp[i] & ~0x20); source
            //.String = String.Replace(left, right, new string(temp)); }

            //else if (source.Action == Tokens.Index.ToString()) if (target.Type == ValueType
            //.Number) { var count = Convert.ToInt32(Math.Abs(target.Number.Round())); if
            //(count > left.Length - 1) throw new InvalidOperationException("Index (" + count
            //+ ") was out of range [" + left.Length + "]."); source.String = left[count]
            //.ToString(); } else source.Number = String.IndexOf(left, right);
            

            //else if (source.Action == Tokens.Less)
            //source.Number = Convert.ToFloat(String
            //.CompareNaturally(left, right) < 0);

            //else if (source.Action == Tokens.More)
            //source.Number = Convert.ToFloat(String
            //.CompareNaturally(left, right) > 0);

            //else if (source.Action == Tokens.LessOrEqual || source
            //.Action == Tokens.NotMore) source.Number = Convert
            //.ToFloat(String.CompareNaturally(left, right) <= 0);

            //else if (source.Action == Tokens.MoreOrEqual || source
            //.Action == Tokens.NotLess) source.Number = Convert
            //.ToFloat(String.CompareNaturally(left, right) >= 0);

            //else if (source.Action == Tokens.Equal)
            //source.Number = Convert.ToFloat(String
            //.CompareNaturally(left, right) == 0);

            //else if (source.Action == Tokens.NotEqual)
            //source.Number = Convert.ToFloat(String
            //.CompareNaturally(left, right) != 0);

            //else if (source.Action == Tokens.And) { source.Number
            //= Convert.ToFloat((source.Type == ValueType.Number ?
            //Convert.ToBoolean(source.Number) : (left.ToLower() ==
            //"true" || left.ToLower() == "1")) && (target.Type ==
            //ValueType.Number ? Convert.ToBoolean(target.Number) :
            //(right.ToLower() == "true" || right == "1"))); }

            //else if (source.Action == Tokens.Xor) { source.Number
            //= Convert.ToFloat((source.Type == ValueType.Number ?
            //Convert.ToBoolean(source.Number) : (left.ToLower() ==
            //"true" || left.ToLower() == "1")) ^ (target.Type ==
            //ValueType.Number ? Convert.ToBoolean(target.Number) :
            //(right.ToLower() == "true" || right == "1"))); }

            //else if (source.Action == Tokens.Or) { source.Number
            //= Convert.ToFloat((source.Type == ValueType.Number ?
            //Convert.ToBoolean(source.Number) : (left.ToLower() ==
            //"true" || left.ToLower() == "1")) || (target.Type ==
            //ValueType.Number ? Convert.ToBoolean(target.Number) :
            //(right.ToLower() == "true" || right == "1"))); }

            //else if (source.Action == Tokens.NotLike)
            //source.Number = Convert.ToFloat(String
            //.CompareNaturally(left.ToLower(), right
            //.ToLower()) != 0);

            //else if (source.Action == Tokens.Like)
            //source.Number = Convert.ToFloat(String
            //.CompareNaturally(left.ToLower(), right
            //.ToLower()) == 0);

            //else if (source.Action == Tokens.LessLike)
            //source.Number = Convert.ToFloat(String
            //.CompareNaturally(left.ToLower(), right
            //.ToLower()) < 0);

            //else if (source.Action == Tokens.MoreLike)
            //source.Number = Convert.ToFloat(String
            //.CompareNaturally(left.ToLower(), right
            //.ToLower()) > 0);

            //else if (source.Action == Tokens.In) source.Number
            //= Convert.ToFloat(String.IndexOf(left, right) != -1);

            //else if (source.Action == Tokens.NotIn) source.Number
            //= Convert.ToFloat(String.IndexOf(left, right) == -1);

            //else if (source.Action == Tokens.Ternary) if (trigger
            //== false) trigger = true; else { source.String = right;
            //if ((source.Type == ValueType.String && (left.ToLower()
            //== "1" || left.ToLower() == "true") || (source.Type ==
            //ValueType.Number && Convert.ToBoolean(source.Number))))
            //trigger = false; }

            //else if (source.Action == Tokens.Convert.ToString()) { if (target
            //.Type == ValueType.Number || (right.ToLower() == "number" || right
            //.ToLower() == "#")) try { var temp = Convert.ToFloat(left); source
            //.Number = temp; } catch { throw new InvalidOperationException("("
            //+ left + ") is not a number."); } else if (right.ToLower() == "list"
            //|| right.ToLower() == "$") try { var temp = Convert.ToList(left); 
            //source.List = temp; } catch { throw new InvalidOperationException
            //("Failed to convert (" + left + ") into a list."); } }
          
            //else if (source.Action == Tokens.OutputAppend || source
            //.Action == Tokens.OutputRedirect) { if (Path.Valid(right)) {
            //Error error; var insufficientPrivileges = new List<string>();
            //var nonTraversible = new List<string>(); bool delimited; var
            //created = new List<string>(); var list = Layout.Open(right,
            //SH.AccessMode, out error, out delimited, ref nonTraversible,
            //ref insufficientPrivileges, ref Layout.ListStub, ref created,
            //false); Layout.ListStub.Clear(); if (delimited) throw new
            //InvalidOperationException("File expected instead of dir" +
            //"ectory [" + Path.Normalize(right) + "]."); if (list.Count
            //== 0 && error != Error.None && error != Error.InvalidName &&
            //created.Count == 0) throw new InvalidOperationException("The"
            //+ " path " + Path.Normalize(right) + (nonTraversible.Count !=
            //0 && insufficientPrivileges.Count == 0 ? " is not traversible."
            //: (nonTraversible.Count == 0 ? " cannot be accessed/created."
            //: " is not accessible."))); var accessible = false; if (source
            //.Action == Tokens.OutputAppend) { for (int i = 0; i < list.Count;
            //i++) if (list[i].Level == 0) { list[i].Node.Content.Data = (list[i]
            //.Node.Content.Data.Decode() + left).Encode(); accessible = true; } }
            //else for (int i = 0; i < list.Count; i++) if (list[i].Level == 0) {
            //list[i].Node.Content.Data = left.Encode(); accessible = true; } if
            //(!accessible) throw new InvalidOperationException("The path " + Path
            //.Normalize(right) + " is not accessible."); source.List = new List
            //<Value>(); for (int j = 0; j < created.Count; j++) source.List.Add
            //(new Value(created[j])); } else throw new InvalidOperationException
            //(Path.Normalize(right) + " is not a valid path."); }

            return trigger;
        }

        public static bool ProcessStrings(Value source, Value target, bool trigger = true)
        {
            var left = source.ToString(); var right = target.ToString();
            
            if (source.Action == Tokens.Add.ToString()) source.String = left + right;

            else if (source.Action == Tokens.Subtract.ToString()) if (target.Type == ValueType
            .Number) { var count = Convert.ToInt32(Math.Abs(target.Number.Round())); if (count
            > left.Length) throw new InvalidOperationException("Index (" + count + ") was " +
            "out of range [" + left.Length + "]."); source.String = left.Remove(left.Length -
            count); } else source.String = String.Replace(left, right, "");

            else if (source.Action == Tokens.Multiply.ToString()) if (target.Type == ValueType
            .Number) for (int i = 1; i < Convert.ToInt32(Math.Abs(target.Number.Round())); i++)   
            source.String += left; else for (int i = 1; i < right.Length; i++) source.String += left;

            else if (source.Action == Tokens.Divide.ToString()) if (target.Type == ValueType
            .Number) { var count = Convert.ToInt32(Math.Abs(target.Number.Round())); if (count >
            left.Length) throw new InvalidOperationException("Split index (" + count + ") was " +
            "out of range [" + left.Length + "]."); source.List = new List<Value>(); var stop =
            Convert.ToInt32(Math.Abs(left.Length / count)); if (left.Length % count != 0) stop++;
            for (int i = 0; i < stop; i++) {source.List.Add(new Value(i == stop - 1 ? left : left
            .Substring(0, count))); if (i != stop - 1) left = left.Remove(0, count); } } else {
            var split = String.Split(left, right); source.List = new List<Value>(); for (int i
            = 0; i < split.Count; i++) source.List.Add(new Value(split[i])); }

            else if (source.Action == Tokens.Remainder.ToString()) if (target.Type == ValueType
            .Number) { var count = Convert.ToInt32(Math.Abs(target.Number.Round())); if (count
            *2 > left.Length) throw new InvalidOperationException("Trim index (" + count + ")" +
            " was out of range [" + left.Length + "]."); source.String = left.Remove(0, count);
            source.String = source.String.Remove(source.String.Length - count); } else { if
            (right == "") return trigger; if (right.Length == 1) source.String = String.Trim(left,
            right[0]); else { while (String.StartsWith(left, right)) left = left.Remove(0, right
            .Length); while (String.EndsWith(left, right)) left = left.Remove(left.Length -
            right.Length); source.String = left; } }

            else if (source.Action == Tokens.Power.ToString()) if (target.Type == ValueType
            .Number) { if (Convert.ToInt32(target.Number.Round()) > 0) source.String = left
            .ToUpper(); else if (Convert.ToInt32(target.Number.Round()) < 0) source.String =
            left.ToLower(); else { source.String = left; } } else { if (right == "") return
            trigger; var temp = right.ToCharArray(); for (int i = 0; i < temp.Length; i++)
            if (temp[i] >= 'A' && temp[i] <= 'Z') temp[i] = (char)(temp[i] | 0x20); else if
            (temp[i] >= 'a' && temp[i] <= 'z') temp[i] = (char)(temp[i] & ~0x20); source
            .String = String.Replace(left, right, new string(temp)); }

            else if (source.Action == Tokens.Index.ToString()) if (target.Type == ValueType
            .Number) { var count = Convert.ToInt32(Math.Abs(target.Number.Round())); if
            (count > left.Length - 1) throw new InvalidOperationException("Index (" + count
            + ") was out of range [" + left.Length + "]."); source.String = left[count]
            .ToString(); } else source.Number = String.IndexOf(left, right);
            

            else if (source.Action == Tokens.Less)
            source.Number = Convert.ToFloat(String
            .CompareNaturally(left, right) < 0);

            else if (source.Action == Tokens.More)
            source.Number = Convert.ToFloat(String
            .CompareNaturally(left, right) > 0);

            else if (source.Action == Tokens.LessOrEqual || source
            .Action == Tokens.NotMore) source.Number = Convert
            .ToFloat(String.CompareNaturally(left, right) <= 0);

            else if (source.Action == Tokens.MoreOrEqual || source
            .Action == Tokens.NotLess) source.Number = Convert
            .ToFloat(String.CompareNaturally(left, right) >= 0);

            else if (source.Action == Tokens.Equal)
            source.Number = Convert.ToFloat(String
            .CompareNaturally(left, right) == 0);

            else if (source.Action == Tokens.NotEqual)
            source.Number = Convert.ToFloat(String
            .CompareNaturally(left, right) != 0);

            else if (source.Action == Tokens.And) { source.Number
            = Convert.ToFloat((source.Type == ValueType.Number ?
            Convert.ToBoolean(source.Number) : (left.ToLower() ==
            "true" || left.ToLower() == "1")) && (target.Type ==
            ValueType.Number ? Convert.ToBoolean(target.Number) :
            (right.ToLower() == "true" || right == "1"))); }

            else if (source.Action == Tokens.Xor) { source.Number
            = Convert.ToFloat((source.Type == ValueType.Number ?
            Convert.ToBoolean(source.Number) : (left.ToLower() ==
            "true" || left.ToLower() == "1")) ^ (target.Type ==
            ValueType.Number ? Convert.ToBoolean(target.Number) :
            (right.ToLower() == "true" || right == "1"))); }

            else if (source.Action == Tokens.Or) { source.Number
            = Convert.ToFloat((source.Type == ValueType.Number ?
            Convert.ToBoolean(source.Number) : (left.ToLower() ==
            "true" || left.ToLower() == "1")) || (target.Type ==
            ValueType.Number ? Convert.ToBoolean(target.Number) :
            (right.ToLower() == "true" || right == "1"))); }

            else if (source.Action == Tokens.NotLike)
            source.Number = Convert.ToFloat(String
            .CompareNaturally(left.ToLower(), right
            .ToLower()) != 0);

            else if (source.Action == Tokens.Like)
            source.Number = Convert.ToFloat(String
            .CompareNaturally(left.ToLower(), right
            .ToLower()) == 0);

            else if (source.Action == Tokens.LessLike)
            source.Number = Convert.ToFloat(String
            .CompareNaturally(left.ToLower(), right
            .ToLower()) < 0);

            else if (source.Action == Tokens.MoreLike)
            source.Number = Convert.ToFloat(String
            .CompareNaturally(left.ToLower(), right
            .ToLower()) > 0);

            else if (source.Action == Tokens.In) source.Number
            = Convert.ToFloat(String.IndexOf(left, right) != -1);

            else if (source.Action == Tokens.NotIn) source.Number
            = Convert.ToFloat(String.IndexOf(left, right) == -1);

            else if (source.Action == Tokens.Ternary) if (trigger
            == false) trigger = true; else { source.String = right;
            if ((source.Type == ValueType.String && (left.ToLower()
            == "1" || left.ToLower() == "true") || (source.Type ==
            ValueType.Number && Convert.ToBoolean(source.Number))))
            trigger = false; }

            else if (source.Action == Tokens.Convert.ToString()) { if (target
            .Type == ValueType.Number || (right.ToLower() == "number" || right
            .ToLower() == "#")) try { var temp = Convert.ToFloat(left); source
            .Number = temp; } catch { throw new InvalidOperationException("("
            + left + ") is not a number."); } else if (right.ToLower() == "list"
            || right.ToLower() == "$") try { var temp = Convert.ToList(left); 
            source.List = temp; } catch { throw new InvalidOperationException
            ("Failed to convert (" + left + ") into a list."); } }
          
            else if (source.Action == Tokens.OutputAppend || source
            .Action == Tokens.OutputRedirect) { if (Path.Valid(right)) {
            Error error; var insufficientPrivileges = new List<string>();
            var nonTraversable = new List<string>(); bool delimited; var
            created = new List<string>(); var list = Layout.Open(right,
            SH.AccessMode, out error, out delimited, ref nonTraversable,
            ref insufficientPrivileges, ref Layout.ListStub, ref created,
            false); Layout.ListStub.Clear(); if (delimited) throw new
            InvalidOperationException("File expected instead of dir" +
            "ectory [" + Path.Normalize(right) + "]."); if (list.Count
            == 0 && error != Error.None && error != Error.InvalidName &&
            created.Count == 0) throw new InvalidOperationException("The"
            + " path " + Path.Normalize(right) + (nonTraversable.Count !=
            0 && insufficientPrivileges.Count == 0 ? " is not traversable."
            : (nonTraversable.Count == 0 ? " cannot be accessed/created."
            : " is not accessible."))); var accessible = false; if (source
            .Action == Tokens.OutputAppend) { for (int i = 0; i < list.Count;
            i++) if (list[i].Level == 0) { list[i].Node.Content.Data = (list[i]
            .Node.Content.Data.Decode() + left).Encode(); accessible = true; } }
            else for (int i = 0; i < list.Count; i++) if (list[i].Level == 0) {
            list[i].Node.Content.Data = left.Encode(); accessible = true; } if
            (!accessible) throw new InvalidOperationException("The path " + Path
            .Normalize(right) + " is not accessible."); source.List = new List
            <Value>(); for (int j = 0; j < created.Count; j++) source.List.Add
            (new Value(created[j])); } else throw new InvalidOperationException
            (Path.Normalize(right) + " is not a valid path."); }

            return trigger;
        }

        static int GetPriority(string operation)
        {
            if (operation == Tokens.Add.ToString() ||
            operation == Tokens.Subtract.ToString()) return 8;

            if (operation == Tokens.Multiply.ToString() || operation == Tokens
            .Divide.ToString() || operation == Tokens.Remainder.ToString()) return 9;

            if (operation == Tokens.Index.ToString()) return 7;

            if (operation == Tokens.Less || operation == Tokens.More ||
            operation == Tokens.LessOrEqual || operation == Tokens.MoreOrEqual
            || operation == Tokens.NotLess || operation == Tokens.NotMore ||
            operation == Tokens.LessLike || operation == Tokens.MoreLike ||
            operation == Tokens.In || operation == Tokens.NotIn) return 6;

            if (operation == Tokens.NotEqual || operation == Tokens.Equal ||
            operation == Tokens.NotLike || operation == Tokens.Like) return 5;

            if (operation == Tokens.And) return 4;
            if (operation == Tokens.Xor) return 3;
            if (operation == Tokens.Or) return 2;

            if (operation == Tokens.Increment || operation == Tokens.Decrement) return 12;

            if (operation == Tokens.Sort || operation == Tokens.Reverse
            || operation == Tokens.Convert.ToString()) return 11;

            if (operation == Tokens.Power.ToString()) return 10;

            if (operation == Tokens.Assignment.ToString() || operation == Tokens.AddAssignment
            || operation == Tokens.SubtractAssignment || operation == Tokens.MultiplyAssignment
            || operation == Tokens.DivideAssignment || operation == Tokens.PowerAssignment ||
            operation == Tokens.RemainderAssignment || operation == Tokens.IndexAssignment ||
            operation == Tokens.ConvertAssignment || operation == Tokens.InputRedirect ||
            operation == Tokens.OutputAppend || operation == Tokens.OutputRedirect) return 0;

            if (operation == Tokens.Ternary) return 1;

            return -1;
        }

        public static Value ProcessChunk(Script source, bool execute = true)
        { if (!source.Valid) return Value.Empty; var start = source.Pointer;
          Value result = null; var once = source.Data[source.Pointer] != Tokens
          .CommandLeft; do { if (source.Proceed(once) > 0) return result ?? new
          Value(); if (!source.Valid) throw new InvalidOperationException("Failed"
          + " to process chunk [" + source.Substring(start, Engine.OutputLimit) +
          "]."); result = source.Execute(!once ? Tokens.ListStop : new[] { Tokens
          .End, Tokens.CommandRight }, execute); if (result.Return || result.Type
          == ValueType.Break || result.Type == ValueType.Continue) return result; }
          while(!once && source.Valid); return result; }

        public static void SkipChunk(Script source)
        { var commandLeft = 1; var commandRight = 0; var enclosed = false; var trigger
          = false; while (commandLeft > commandRight) { if (!source.Valid) return; var
          previous = source.Pointer - 1 < 0 ? Tokens.Empty : source.Data[source.Pointer
          - 1]; var current = source.Data[source.Pointer++]; if (!enclosed && current
          == Tokens.End && !trigger) commandRight++; if (!enclosed && current == Tokens
          .CommandLeft) { if (trigger) commandLeft++; else trigger = true; } else if
          (!enclosed && current == Tokens.CommandRight) commandRight++; else if (current
          == Tokens.VerbatimString && (/*previous == Tokens.Empty*/!enclosed || (previous != Tokens
          .MirrorLeft && previous != Tokens.MirrorRight))) enclosed = !enclosed; } }

        public static void SkipParameters(Script source)
        { var parameterLeft = 0; var parameterRight = 0; var enclosed = false; while
          (parameterLeft == 0 || parameterLeft > parameterRight) { if (!source.Valid)
          return; var previous = source.Pointer - 1 < 0 ? Tokens.Empty : source.Data
          [source.Pointer - 1]; var next = source.Data[source.Pointer++]; if (!enclosed
          && next == Tokens.ParameterLeft) parameterLeft++; else if (!enclosed && next
          == Tokens.ParameterRight && parameterLeft != 0) parameterRight++; else if
          (next == Tokens.VerbatimString && (!enclosed || (previous != Tokens.MirrorLeft
          && previous != Tokens.MirrorRight))) enclosed = !enclosed; } }

        public static void SkipElse(Script source)
        { while (source.Valid) { var temp = new Script(source); var token = temp
          .GetConstruct(); var elseCondition = token == Tokens.Else; var elseShort
          = String.StartsWith(token, Tokens.ElseShort); var elseIfCondition = token
          == Tokens.ElseIf; if (!elseShort && !elseIfCondition && !elseCondition)
          return; if (elseShort) source.Pointer += Tokens.ElseShort.Length; else
          if (elseIfCondition) source.Pointer += Tokens.ElseIf.Length; else source
          .Pointer += Tokens.Else.Length + 1; if (source.Data[source.Pointer] ==
          Tokens.ParameterLeft) SkipParameters(source); temp = new Script(source);
          token = temp.GetConstruct(); if (token == Tokens.If || (String.StartsWith
          (token, Tokens.IfShort) && !String.StartsWith(token, Tokens.ElseShort)))
          SkipIf(source); else if (token == Tokens.Loop || String.StartsWith(token,
          Tokens.LoopShort.ToString())) SkipLoops(source); else if (token == Tokens
          .Try || (temp.Pointer + 1 < temp.Data.Length && (temp.Data[temp.Pointer]
          .ToString() + temp.Data[temp.Pointer + 1]) == Tokens.TryShort)) SkipTry
          (source); else { var skip = false; for (int i = 0; i < Commands.List[0]
          .Count; i++) { var key = Commands.List[0][i].Key; if (String.StartsWith
          (token, key + Tokens.Dot) || token == key) { skip = true; break; } for
          (int j = 0; j < Commands.List[0][i].Aliases.Length; j++) { var alias =
          Commands.List[0][i].Aliases[j]; if (String.StartsWith(token, alias +
          Tokens.Dot)) { skip = true; break; } } } if (skip) SkipShell(source);
          else SkipChunk(source); } } }

        public static void SkipIf(Script source, int counter = 0)
        { while (source.Valid) { var temp = new Script(source); var token = temp
          .GetConstruct(); var elseCondition = token == Tokens.Else; var elseShort
          = String.StartsWith(token, Tokens.ElseShort); var elseIfCondition = token
          == Tokens.ElseIf; var ifCondition = token == Tokens.If; var ifShort =
          !elseShort && String.StartsWith(token, Tokens.IfShort); if (!elseCondition
          && !elseShort && !elseIfCondition && !ifCondition && !ifShort) return; if
          (elseIfCondition || (elseShort && (source.Pointer + Tokens.ElseShort.Length
          < source.Data.Length) && source.Data[source.Pointer + Tokens.ElseShort
          .Length] == Tokens.ParameterLeft)) source.Pointer += elseIfCondition ?
          Tokens.ElseIf.Length : Tokens.ElseShort.Length; else if (ifCondition ||
          ifShort) { counter++; source.Pointer += ifShort ? Tokens.IfShort.Length :
          Tokens.If.Length; } else { counter--; source.Pointer += elseCondition ?
          Tokens.Else.Length + 1 : Tokens.ElseShort.Length; } if (source.Data[source
          .Pointer] == Tokens.ParameterLeft) SkipParameters(source); temp = new Script
          (source); SkipChunk(source); if (ifCondition || ifShort) { temp = new Script
          (temp.Data.Substring(temp.Pointer, source.Pointer - temp.Pointer)); if (temp
          .Data[temp.Pointer] != Tokens.CommandLeft) while (temp.Valid) { token = temp
          .GetConstruct(); if (token == Tokens.If || (String.StartsWith(token, Tokens
          .IfShort) && !String.StartsWith(token, Tokens.ElseShort))) counter++; else if
          (token == Tokens.Loop || String.StartsWith(token, Tokens.LoopShort.ToString()
          )) SkipLoops(source); else if (token == Tokens.Try || (temp.Pointer + 1 < temp
          .Data.Length && (temp.Data[temp.Pointer].ToString() + temp.Data[temp.Pointer + 1])
          == Tokens.TryShort)) { if (token != Tokens.Try) temp.Traverse(1); SkipTry(source);
          } else { var skip = false; for (int i = 0; i < Commands.List[0].Count; i++) { var
          key = Commands.List[0][i].Key; if (String.StartsWith(token, key + Tokens.Dot) ||
          token == key) { skip = true; break; } for (int j = 0; j < Commands.List[0][i]
          .Aliases.Length; j++) { var alias = Commands.List[0][i].Aliases[j]; if (String
          .StartsWith(token, alias + Tokens.Dot)) { skip = true; break; } } } if (skip)
          SkipShell(source); else break; } if (temp.Data[temp.Pointer] == Tokens.CommandLeft
          || temp.Data[temp.Pointer] == Tokens.CommandRight) break; SkipParameters(temp); 
          } } if (counter <= 0) return; } }

        public static Value ProcessConditional(Script source)
        { var start = source.Pointer; var result = source.Execute(Tokens.ParameterRight);
          Script temp; string next; if (result.Type == ValueType.List ? (result.List[result
          .List.Count - 1].Type == ValueType.Number ? Convert.ToBoolean(result.List[result
          .List.Count - 1].Number) : (result.List[result.List.Count - 1].String == "1" ||
          result.List[result.List.Count - 1].String.ToLower() == "true")) : Convert.ToBoolean
          (result.Number)) { result = ProcessChunk(source); if (result.Return) return result;
          if (result.Type == ValueType.Break || result.Type == ValueType.Continue) { source
          .Pointer = start; temp = new Script(source); next = temp.GetConstruct(); if (next
          == Tokens.If || (String.StartsWith(next, Tokens.IfShort) && !String.StartsWith(next,
          Tokens.ElseShort))) SkipIf(source); else if (next == Tokens.Loop || String.StartsWith
          (next, Tokens.LoopShort.ToString())) SkipLoops(source); else if (next == Tokens.Try ||
          (temp.Pointer + 1 < temp.Data.Length && (temp.Data[temp.Pointer].ToString() + temp.Data
          [temp.Pointer + 1]) == Tokens.TryShort)) SkipTry(source); else { var skip = false; for
          (int i = 0; i < Commands.List[0].Count; i++) { var key = Commands.List[0][i].Key; if
          (String.StartsWith(next, key + Tokens.Dot) || next == key) { skip = true; break; } for
          (int j = 0; j < Commands.List[0][i].Aliases.Length; j++) { var alias = Commands.List[0]
          [i].Aliases[j]; if (String.StartsWith(next, alias + Tokens.Dot)) { skip = true; break; 
          } } } if (skip) SkipShell(source); else SkipChunk(source); } } else if (source.Data
          [source.Pointer] == Tokens.End || source.Data[source.Pointer] == Tokens.CommandRight)
          source.Traverse(1); SkipElse(source); if (!Array.Contains(Tokens.ListStop, source.Data
          [source.Pointer])) source.Traverse(-1); return result; } temp = new Script(source); next
          = temp.GetConstruct(); if (next == Tokens.If || (String.StartsWith(next, Tokens.IfShort)
          && !String.StartsWith(next, Tokens.ElseShort))) SkipIf(source); else if (next == Tokens
          .Loop || String.StartsWith(next, Tokens.LoopShort.ToString())) SkipLoops(source); else if
          (next == Tokens.Try || (temp.Pointer + 1 < temp.Data.Length && (temp.Data[temp.Pointer]
          .ToString() + temp.Data[temp.Pointer + 1]) == Tokens.TryShort)) SkipTry(source); else {
          var skip = false; for (int i = 0; i < Commands.List[0].Count; i++) { var key = Commands
          .List[0][i].Key; if (String.StartsWith(next, key + Tokens.Dot) || next == key) { skip =
          true; break; } for (int j = 0; j < Commands.List[0][i].Aliases.Length; j++) { var alias
          = Commands.List[0][i].Aliases[j]; if (String.StartsWith(next, alias + Tokens.Dot)) { skip
          = true; break; } } } if (skip) SkipShell(source); else SkipChunk(source); } temp = new
          Script(source); start = source.Pointer; next = temp.GetConstruct(); result = Value.Empty;
          if (next == Tokens.ElseIf || (String.StartsWith(next, Tokens.ElseShort) && (source.Pointer
          + Tokens.ElseShort.Length < source.Data.Length) && source.Data[source.Pointer + Tokens    
          .ElseShort.Length] == Tokens.ParameterLeft)) { source.Pointer = start + (next == Tokens
          .ElseIf ? Tokens.ElseIf.Length : Tokens.ElseShort.Length); source.Pointer++; result =
          ProcessConditional(source); } else if (next == Tokens.Else || String.StartsWith(next,
          Tokens.ElseShort)) { source.Pointer = start + (next == Tokens.Else ? Tokens.Else.Length
          + 1: Tokens.ElseShort.Length); result = ProcessChunk(source); } if (result.Return) return
          result; if (result.Type == ValueType.Break || result.Type == ValueType.Continue) { source
          .Pointer = start; temp = new Script(source); next = temp.GetConstruct(); if (next == Tokens
          .If || (String.StartsWith(next, Tokens.IfShort) && !String.StartsWith(next, Tokens.ElseShort
          ))) SkipIf(source); else if (next == Tokens.Loop || String.StartsWith (next, Tokens.LoopShort
          .ToString())) SkipLoops(source); else if (next == Tokens.Try || (temp.Pointer + 1 < temp.Data
          .Length && (temp.Data[temp.Pointer].ToString() + temp.Data[temp.Pointer + 1]) == Tokens
          .TryShort)) SkipTry(source); else { var skip = false; for (int i = 0; i < Commands.List[0]
          .Count; i++) { var key = Commands.List[0][i].Key; if (String.StartsWith(next, key + Tokens
          .Dot) || next == key) { skip = true; break; } for (int j = 0; j < Commands.List[0][i].Aliases
          .Length; j++) { var alias = Commands.List[0][i].Aliases[j]; if (String.StartsWith(next, alias
          + Tokens.Dot)) { skip = true; break; } } } if (skip) SkipShell(source); else SkipChunk(source);
          } } SkipElse(source); if (!Array.Contains(Tokens.ListStop, source.Data[source.Pointer])) source
          .Traverse(-1); return result; }

        public static void SkipLoops(Script source, bool skipElse = false)
        { while (source.Valid) { var temp = new Script(source); var token = temp.GetConstruct
          (); var loop = token == Tokens.Loop; var loopShort = String.StartsWith(token, Tokens
          .LoopShort.ToString()); var ifCondition = token == Tokens.If || (!String.StartsWith
          (token, Tokens.ElseShort) && String.StartsWith(token, Tokens.IfShort)); var _try =
          token == Tokens.Try || (temp.Pointer + 1 < temp.Data.Length && (temp.Data[temp.Pointer]
          .ToString() + temp.Data[temp.Pointer + 1]) == Tokens.TryShort); if (temp.Data[temp
          .Pointer] == Tokens.End || temp.Data[temp.Pointer] == Tokens.CommandRight) { source
          .Traverse(1); if (skipElse) SkipElse(source); return; } if ((!loop && !loopShort && /*!loopShort*/
          !ifCondition) || (temp.Data[temp.Pointer] == Tokens.CommandLeft)) { SkipChunk(source);
          if (skipElse) SkipElse(source); return; } if (loop) source.Pointer += Tokens.Loop
          .Length; else if (loopShort) source.Pointer++; else if (_try) { SkipTry(source);
          return; } else { var skip = false; for (int i = 0; i < Commands.List[0].Count; i++)
          { var key = Commands.List[0][i].Key; if (String.StartsWith(token, key + Tokens.Dot)
          || token == key) { skip = true; break; } for (int j = 0; j < Commands.List[0][i]
          .Aliases.Length; j++) { var alias = Commands.List[0][i].Aliases[j]; if (String
          .StartsWith(token, alias + Tokens.Dot)) { skip = true; break; } } } if (skip)
          SkipShell(source); else { SkipIf(source); return; } } SkipParameters(source); } }

        public static Value ProcessWhile(Script source)
        { var start = source.Pointer; var until = HAL.RTC.Second + 1; Value value, result =
          Value.Empty; if (until > 59) until -= 60; while (true) { HAL.Keyboard.KeyMapping
          mapping; if (HAL.Global.Keyboard.GetMapping(out mapping) && mapping != null) if
          (mapping.Key == ConsoleKey.Escape) throw new OperationCanceledException("Operation"
          + " canceled by user."); if (until == HAL.RTC.Second || until == HAL.RTC.Second -
          1) { UI.DrawClock(false); until = HAL.RTC.Second + 1; if (until > 59) until -= 60;
          } source.Pointer = start; value = source.Execute(Tokens.ParameterRight); if (value
          .Type == ValueType.List ? (value.List[value.List.Count - 1].Type == ValueType.Number
          ? !Convert.ToBoolean(value.List[value.List.Count - 1].Number) : (value.List[value
          .List.Count - 1].String != "1" && value.List[value.List.Count - 1].String.ToLower
          () != "true")) : !Convert.ToBoolean(value.Number)) break; result = ProcessChunk
          (source); if (result.Return) return result; if (result.Type == ValueType.Break)
          break; } source.Pointer = start - 1; SkipParameters(source); SkipLoops(source,
          true); if (!Array.Contains(Tokens.ListStop, source.Data[source.Pointer])) source
          .Traverse(-1); return result; }

        public static Value ProcessForeach(Script source, string condition)
        { Value value, result = Value.Empty; var counter = 0; var index = -1; var trigger =
          false; var temp = ""; for (int i = 0; i < condition.Length; i++) { if (condition[i]
          == Tokens.VerbatimString && (!trigger || (condition[i - 1] != Tokens.MirrorLeft &&
          condition[i - 1] != Tokens.MirrorRight))) trigger = !trigger; else if (!trigger &&
          condition[i] == Tokens.Index && ((i + 1 < condition.Length && condition[i + 1] ==
          Tokens.Index) || (i - 1 >= 0 && condition[i - 1] == Tokens.Index))) if (index == -1)
          index = i; else continue; temp += condition[i]; } condition = temp; if (index == -1)
          { temp = ""; value = new Script(condition).ExecuteAll(); } else if (index == 0) {
          temp = ""; value = new Script(condition.Remove(0, 1)).ExecuteAll(); } else if (index
          == condition.Length - 1) { temp = ""; value = new Script(condition.Remove(index, 1))
          .ExecuteAll(); } else { temp = condition.Substring(0, index); value = new Script
          (condition.Remove(0, index + 1)).ExecuteAll(); } if (value.Type == ValueType.Number)
          counter = Convert.ToInt32(value.Number.Round()); else if (value.Type == ValueType
          .String) counter = value.String.Length - 1; else if (value.Type == ValueType.List)
          counter = value.List.Count - 1; if (temp != "") Function.AddVariable(temp, new
          Variable(Value.Empty)); var start = source.Pointer; var until = HAL.RTC.Second +
          1; if (until > 59) until -= 60; if (counter > 0) { if (temp == "") counter--; for
          (index = 0; index <= counter; index++) { HAL.Keyboard.KeyMapping mapping; if (HAL
          .Global.Keyboard.GetMapping(out mapping) && mapping != null) if (mapping.Key ==
          ConsoleKey.Escape) throw new OperationCanceledException("Operation canceled by " +
          "user."); if (until == HAL.RTC.Second || until == HAL.RTC.Second - 1 ) { UI.DrawClock
          (false); until = HAL.RTC.Second + 1; if (until > 59) until -= 60; } source.Pointer =
          start; if (temp != "") if (value.Type == ValueType.Number) Function.AddVariable(temp, new
          Variable(new Value(index))); else if (value.Type == ValueType.String) Function.AddVariable
          (temp, new Variable(new Value(value.String[index].ToString()))); else if (value.Type ==
          ValueType.List) Function.AddVariable(temp, new Variable(new Value(value.List[index])));
          result = ProcessChunk(source); if (result.Return) return result; if (result.Type == ValueType
          .Break) break; } source.Pointer = start; SkipLoops(source, true); if (!Array.Contains(Tokens
          .ListStop, source.Data[source.Pointer])) source.Traverse(-1); return result; } if (temp == "")
          counter++; for (index = 0; index >= counter; index--) { HAL.Keyboard.KeyMapping mapping; if
          (HAL.Global.Keyboard.GetMapping(out mapping) && mapping != null) if (mapping.Key == ConsoleKey
          .Escape) throw new OperationCanceledException("Warning: Operation canceled by user."); if
          (until == HAL.RTC.Second || until == HAL.RTC.Second - 1 ) { UI.DrawClock(false); until = HAL
          .RTC.Second + 1; if (until > 59) until -= 60; } source.Pointer = start; if (temp != "" &&
          value.Type == ValueType.Number) Function.AddVariable(temp, new Variable(new Value(index)));
          result = ProcessChunk(source); if (result.Return) return result; if (result.Type == ValueType
          .Break) break; } source.Pointer = start; SkipLoops(source, true); if (!Array.Contains(Tokens
          .ListStop, source.Data[source.Pointer])) source.Traverse(-1); return result; }

        public static Value ProcessFor(Script source, List<string> conditions)
        { Value value = Value.Empty, result = Value.Empty; new Script(conditions[0]).ExecuteAll();
          var start = source.Pointer; var until = HAL.RTC.Second + 1; if (until > 59) until -= 60;
          var nullCondition = String.Replace(conditions[1], Tokens.End.ToString(), "") == ""; var
          test = new Script(conditions[1]); var scripts = new List<Script>(); for (int i = 2; i <
          conditions.Count; i++) scripts.Add(new Script(conditions[i])); while (true) { HAL.Keyboard
          .KeyMapping mapping; if (HAL.Global.Keyboard.GetMapping(out mapping) && mapping != null)
          if (mapping.Key == ConsoleKey.Escape) throw new OperationCanceledException("Operation"
          + " canceled by user."); if (until == HAL.RTC.Second || until == HAL.RTC.Second - 1) {
          UI.DrawClock(false); until = HAL.RTC.Second + 1; if (until > 59) until -= 60; } source
          .Pointer = start; if (!nullCondition) { value = test.ExecuteAll(); if (value.Type ==
          ValueType.List ? (value.List[value.List.Count - 1].Type == ValueType.Number ? !Convert
          .ToBoolean(value.List[value.List.Count - 1].Number) : (value.List[value.List.Count - 1]
          .String != "1" && value.List[value.List.Count - 1].String.ToLower() != "true")) : !Convert
          .ToBoolean(value.Number)) break; } result = ProcessChunk(source); if (result.Return) return
          result; if (result.Type == ValueType.Break) break; for (int i = 0; i < scripts.Count; i++)
          scripts[i].ExecuteAll(); } SkipLoops(source, true); if (!Array.Contains(Tokens.ListStop,
          source.Data[source.Pointer])) source.Traverse(-1); return result; }

        public static void SkipTry(Script source)
        { if (!source.Valid) throw new InvalidOperationException("Failed to skip chunk [" +
          source.Substring(source.Pointer, Engine.OutputLimit) + "]."); var temp = new Script
          (source); var token = temp.GetConstruct(); if (token != Tokens.Try && (temp.Pointer
          + 1 >= temp.Data.Length || (temp.Data[temp.Pointer].ToString() + temp.Data[temp
          .Pointer + 1]) != Tokens.TryShort)) return; source.Pointer += token == Tokens.Try
          ? Tokens.Try.Length : Tokens.TryShort.Length; if (source.Data[source.Pointer] ==
          Tokens.ParameterLeft) SkipParameters(source); if (source.Data[source.Pointer] ==
          Tokens.CommandLeft) SkipChunk(source); if (source.Data[source.Pointer] == Tokens
          .CommandLeft) SkipChunk(source); }

        public static Value ProcessTry(Script source)
        { source.Traverse(-1); var start = source.Pointer; var level = Functions.Stack.Count; Exception
          exception = null; var result = Value.Empty; var value = new Variable(Value.Empty); var variable
          = ""; if (source.Data[start] == Tokens.ParameterLeft) { source.Traverse(1); variable = source
          .GetConstruct(); source.Pointer = start; SkipParameters(source); } if (source.Data[source.Pointer]
          == Tokens.CommandLeft) { if (!string.IsNullOrEmpty(variable)) Function.AddVariable(variable, value);
          try { result = ProcessChunk(source); } catch (InvalidOperationException temp) { exception = temp; }
          } else throw new InvalidOperationException(string.IsNullOrEmpty(variable) ? "Invalid definition of"
          + "the try{...}{...} block." : "Invalid definition of the try(" + variable + "){...}{...} block.");
          if (result.Return) return result; if (exception != null || result.Type == ValueType.Break || result
          .Type == ValueType.Continue) { source.Pointer = start; SkipChunk(source); } if (source.Data[source
          .Pointer] == Tokens.CommandLeft) { if (exception != null) { var stack = ""; var top = Functions
          .Stack.Count; for (int i = 0; i < Functions.Stack.Count; i++) { if (top-- < level) break; if (string
          .IsNullOrWhiteSpace(Functions.Stack[i].Key)) continue; stack = Tokens.Space + Symbols.AngleQuoteRight
          + Tokens.Space + Functions.Stack[i].Key + Tokens.ParameterLeft + Tokens.ParameterRight + stack; } if
          (!string.IsNullOrWhiteSpace(stack)) stack = stack.Remove(0, (Tokens.Space + Symbols.AngleQuoteRight +
          Tokens.Space).Length); while (Functions.Stack.Count > level) Functions.Stack.RemoveAt(Functions.Stack
          .Count - 1); value.Value = new Value(exception.Message + Tokens.Space + Tokens.Convert + Tokens.Space +
          stack); result = ProcessChunk(source); if (Functions.Stack.Count != 0 && !string.IsNullOrEmpty(variable))
          { var local = Functions.Stack[Functions.Stack.Count - 1].Functions; for (int i = 0; i < local.Count;
          i++) if (local[i].Name == variable) local.RemoveAt(i); } } else SkipChunk(source); } return result; }

        public static void ExtendList(Value parent, List<Value> specifiers, int level, Value value)
        { if (specifiers.Count <= level) return; parent.Type = ValueType.List; if (parent.List == null)
          parent.List = new List<Value>(); var index = parent.ElementIndex(specifiers[level]); if (index
          < 0) index = parent.AddElement(specifiers[level].ToString(), new Value()); else if (parent.List
          .Count <= index) for (int i = parent.List.Count; i <= index; i++) parent.List.Add(new Value());
          if (specifiers.Count - 1 == level) { parent.List[index] = value; return; } ExtendList(parent.List
          [index], specifiers, level + 1, value); }

        public static void SkipShell(Script source)
        { if (!source.Valid) throw new InvalidOperationException("Failed to skip chunk [" + source
          .Substring(source.Pointer, Engine.OutputLimit) + "]."); var skip = false; var temp = new
          Script(source); var token = temp.GetConstruct(); for (int i = 0; i < Commands.List[0].Count;
          i++) { var key = Commands.List[0][i].Key; if (String.StartsWith(token, key + Tokens.Dot)
          || token == key) { skip = true; break; } for (int j = 0; j < Commands.List[0][i].Aliases
          .Length; j++) { var alias = Commands.List[0][i].Aliases[j]; if (String.StartsWith(token,
          alias + Tokens.Dot)) { skip = true; break; } } } if (!skip) return; if (source.Data[source
          .Pointer - 1] != Tokens.Dot && source.Data[source.Pointer] == Tokens.Dot) source.Traverse
          (1); if (source.Data[source.Pointer - 1] == Tokens.Dot) { for (int i = source.Pointer; i <
          source.Data.Length; i++) { if (source.Data[i] == Tokens.CommandLeft || source.Data[i] ==
          Tokens.Space) { source.Pointer = i + 1; break; } if (source.Data[i] == Tokens.CommandRight
          || source.Data[i] == Tokens.Separator || source.Data[i] == Tokens.End) { source.Pointer =
          i; break; } } } if (source.Data[source.Pointer] != Tokens.End && source.Data[source.Pointer]
          != Tokens.Separator && source.Data[source.Pointer] != Tokens.CommandRight) { var trigger =
          false; int commandLeft = 0, commandRight = 0; while (source.Pointer < source.Data.Length)
          { if (source.Data[source.Pointer] == Tokens.VerbatimString && (source.Pointer - 1 < 0 ||
          (source.Data [source.Pointer - 1] != Tokens.MirrorLeft && source.Data[source.Pointer - 1] !=
          Tokens.MirrorRight))) trigger = !trigger; else if (!trigger && source.Data[source.Pointer] ==
          Tokens.CommandLeft) commandLeft++; else if (!trigger && source.Data[source.Pointer] == Tokens
          .CommandRight) { commandRight++; if (commandLeft == commandRight) commandLeft = commandRight
          = 0; else if (commandLeft < commandRight) break; } else if (!trigger && (source.Data[source
          .Pointer] == Tokens.End || source.Data[source.Pointer] == Tokens.Separator) && commandLeft ==
          0 && commandRight == 0) break; source.Traverse(1); } } if (source.Valid) source.Traverse(1); }

        public static void CheckShell(Script source, string command, int before)
        { Error error; int level = 0, commandLeft = 0, commandRight = 0; if (source.Data
          [source.Pointer - 1] == Tokens.CommandLeft) source.Traverse(-1); else if (source
          .Data[source.Pointer - 1] != Tokens.Dot && source.Data[source.Pointer] == Tokens
          .Dot) source.Traverse(1); if (source.Data[source.Pointer - 1] == Tokens.Dot) { 
          level++; command += Tokens.Dot; for (int i = source.Pointer; i < source.Data
          .Length; i++) { if (source.Data[i] == Tokens.Dot && command[command.Length - 1]
          != Tokens.Dot) level++; else if (source.Data[i] == Tokens.CommandLeft || source
          .Data[i] == Tokens.Space) { source.Pointer = i + 1; break; } else if (source.Data
          [i] == Tokens.CommandRight || source.Data[i] == Tokens.Separator || source.Data
          [i] == Tokens.End) { source.Pointer = i; break; } if (source.Data[i] != Tokens
          .Dot || command[command.Length - 1] != Tokens.Dot) command += source.Data[i]; }
          if (command [command.Length - 1] == Tokens.Dot) { command = command.Remove(command
          .Length - 1, 1); level--; } } var entry = Command.Find(level, command.Remove(0,
          command.LastIndexOf(Tokens.Dot) == - 1 ? 0 : command.LastIndexOf(Tokens.Dot) + 1),
          out error); if (entry == null) { if (error == Error.WrongLevel || error == Error
          .NotFound) throw new InvalidOperationException("Command (" + command + ") not "
          + "found."); throw new InvalidOperationException("Failed to invoke command (" +
          command + ")."); } if (source.Data[source.Pointer] == Tokens.Separator || source
          .Data[source.Pointer] == Tokens.End || source.Data[source.Pointer] == Tokens
          .CommandRight) source.Traverse(1); else { var trigger = false; while (source
          .Pointer < source.Data.Length) { if (source.Data[source.Pointer] == Tokens
          .VerbatimString && (source.Pointer - 1 < 0 || (source.Data [source.Pointer - 1]
          != Tokens.MirrorLeft && source.Data[source.Pointer - 1] != Tokens.MirrorRight)))
          trigger = !trigger; else if (!trigger && source.Data[source.Pointer] == Tokens
          .CommandLeft) { if (commandLeft == 0) level = source.Pointer + 1; commandLeft++;
          } else if (!trigger && source.Data[source.Pointer] == Tokens.CommandRight) { 
          commandRight++; if (commandLeft == commandRight) { commandLeft = commandRight =
          0; if (!new Script(Script.Normalize(source.Data.Substring(level, source.Pointer -
          level))).CheckAll()) throw new InvalidOperationException("Invalid parameters " +
          "passed to (" + command + ").");} else if (commandLeft < commandRight) break; }
          else if (!trigger && (source.Data[source.Pointer] == Tokens.End || source.Data
          [source.Pointer] == Tokens.Separator) && commandLeft == 0 && commandRight == 0)
          break; source.Traverse(1); } source.Pointer = before; if (Array.Contains(Tokens
          .ListProcess, source.Data[source.Pointer])) source.Traverse(1); SkipShell(source); } }

        public static void CheckConditional(Script source, bool state)
        { if (!source.Check(Tokens.ParameterRight)) throw new InvalidOperationException("Invalid "
          + "condition encountered."); if (state) { ProcessChunk(source, false); if (source.Data
          [source.Pointer] == Tokens.End || source.Data[source.Pointer] == Tokens.CommandRight)
          source.Traverse(1); SkipElse(source); return; } var temp = new Script(source); var next
          = temp.GetConstruct(); if (next == Tokens.If || (String.StartsWith(next, Tokens.IfShort)
          && !String.StartsWith(next, Tokens.ElseShort))) SkipIf(source); else if (next == Tokens
          .Loop || String.StartsWith(next, Tokens.LoopShort.ToString())) SkipLoops(source); else if
          (next == Tokens.Try || (temp.Pointer + 1 < temp.Data.Length && (temp.Data[temp.Pointer]
          .ToString() + temp.Data[temp.Pointer + 1]) == Tokens.TryShort)) SkipTry(source); else {
          var skip = false; for (int i = 0; i < Commands.List[0].Count; i++) { var key = Commands
          .List[0][i].Key; if (String.StartsWith(next, key + Tokens.Dot) || next == key) { skip =
          true; break; } for (int j = 0; j < Commands.List[0][i].Aliases.Length; j++) { var alias
          = Commands.List[0][i].Aliases[j]; if (String.StartsWith(next, alias + Tokens.Dot)) { skip
          = true; break; } } } if (skip) SkipShell(source); else SkipChunk(source); } temp = new
          Script(source); var start = source.Pointer; next = temp.GetConstruct(); if (next == Tokens
          .ElseIf || (String.StartsWith(next, Tokens.ElseShort) && (source.Pointer + Tokens.ElseShort
          .Length < source.Data.Length) && source.Data[source.Pointer + Tokens.ElseShort.Length] ==
          Tokens.ParameterLeft)) { source.Pointer = start + (next == Tokens.ElseIf ? Tokens.ElseIf
          .Length : Tokens.ElseShort.Length); source.Pointer++; var currentPointer = source.Pointer;
          CheckConditional(source, true); source.Pointer = currentPointer; CheckConditional(source,
          false); } else if (next == Tokens.Else || String.StartsWith(next, Tokens.ElseShort)) { 
          source.Pointer = start + (next == Tokens.Else ? Tokens.Else.Length + 1: Tokens.ElseShort
          .Length); ProcessChunk(source, false); } SkipElse(source); }

        public static void CheckTry(Script source, int before)
        { source.Traverse(-1); var start = source.Pointer; Exception exception = null; var
          variable = ""; if (source.Data[start] == Tokens.ParameterLeft) { source.Traverse(1);
          variable = source.GetConstruct(); source.Pointer = start; SkipParameters(source); }
          if (source.Data[source.Pointer] == Tokens.CommandLeft) try { ProcessChunk(source, false);
          } catch (Exception temp) { exception = temp; } else throw new InvalidOperationException
          (string.IsNullOrEmpty(variable) ? "Invalid definition of the try{...}{...} block." :
          "Invalid definition of the try(" + variable + "){...}{...} block."); if (source.Data
          [source.Pointer] == Tokens.CommandLeft) { if (exception != null) { ProcessChunk(source,
          false); } else SkipChunk(source); } source.Pointer = before; SkipTry(source); }

        public static void CheckLoop(Script source, int before)
        { if (!source.Check(Tokens.ParameterRight)) throw new
          InvalidOperationException("Invalid loop condition.");
          ProcessChunk(source, false); source.Pointer = before;
          SkipLoops(source, true); }

        public static void CheckFunction(Script source, int before)
        { if (source.Data[source.Pointer] == Tokens.ParameterLeft) CheckStatement
          (source); else {  source.GetConstruct(Tokens.Separators); if (source.Valid
          && (source.Data[source.Pointer] == Tokens.ParameterLeft || source.Data
          [source.Pointer] == Tokens.Space)) source.Traverse(1); var stop = String
          .IndexOfAny(source.Data, new[] { Tokens.ParameterRight }, source.Pointer);
          if (stop < 0) throw new InvalidOperationException("Incomplete function "
          + "definition encountered."); source.Pointer = stop + 1; if (source.Valid
          && (source.Data[source.Pointer] == Tokens.CommandLeft || source.Data[source
          .Pointer] == Tokens.Space)) source.Traverse(1); source.GetChunk(Tokens
          .CommandLeft, Tokens.CommandRight); } }

        public static void CheckStatement(Script source)
        { var currentPointer = source.Pointer; if (source.Data[source.Pointer] == Tokens
          .ParameterLeft) { source.Traverse(1); if(!source.Check(Tokens.ParameterRight))
          throw new InvalidOperationException("Invalid parameters encountered."); } else
          ProcessChunk(source, false); source.Pointer = currentPointer; if (source.Data
          [source.Pointer] == Tokens.ParameterLeft) SkipParameters(source); SkipChunk
          (source); }
    }
}
